package com.foo.designpattern.state.state2;

import com.foo.designpattern.state.state2.VoteManager;
import junit.framework.TestCase;

/**
 * com.foo.designpattern.state
 * Created with IntelliJ IDEA.
 * Created by jiang on 2016-06-08 15:57.
 *
 * @Description 测试类：状态模式(State)--在状态的处理类中进行状态的维护和转换
 * 状态模式：又称状态对象模式(Pattern of Object for States)，状态模式是对象的行为模式。
 * 状态模式允许一个对象在其内部状态改变的时候改变其行为，这个对象看上去就像是改变了它的类一样。
 * 状态模式把所研究的对象的行为包装在不同的状态对象里，每一个状态对象都属于一个抽象状态类的一个子类。
 * <p/>
 * 状态模式所涉及的角色有：
 * 1、环境(Context)角色：也称为上下文，定义客户端所感兴趣的接口，并且保留一个具体状态类的实例。
 * 这个具体状态类的实例给出环境对象的现有状态。
 * 2、抽象状态(State)角色：定义一个接口，用用以封装环境(Context)对象的一个特定的状态所对应的行为。
 * 3、具体状态(ConcreteState)角色：每一个具体状态类都实现了环境(Context)的一个状态所对应的行为。
 * <p/>
 * 状态处理对象的创建和销毁：
 * 1、当需要使用状态对象的时候创建，使用完后就销毁；
 * 2、提前创建它们并永不销毁；
 * 3、采用 延时加载+缓存 的方式。就是当第一次使用的时候创建，使用完后并不销毁而是把它缓存起来，
 * 下一次使用时，从缓存中获取对象，并由缓存框架来销毁状态处理对象。
 * <p/>
 * 状态的维护和转换：
 * 维护状态的数据，给状态设置不同的状态值；状态的转换，指的是根据状态的变化来选择不同的状态处理对象。
 * 有两个地方可以进行状态的维护和转换：
 * 1、在Context中进行状态的维护和转换；
 * 2、在状态的处理类中进行状态的维护和转换。
 * 如何选择这两种方式：
 * 1、如果状态转换的规则是一定的，一般不需要进行什么扩展规则，那么就适合在上下文中统一进行状态的维护；
 * 2、如果状态的转换取决于前一个状态处理的结果，或者是依赖外部数据，为了增强灵活性，这种情况下，一般是在状态处理类中进行状态的维护。
 * <p/>
 * 本例是在状态的处理类中进行状态的维护和转换
 * <p/>
 * 本例考虑一个在线投票系统的应用，要实现控制同一个用户只能投一票，如果一个用户反复投票，而且投票次数超过五次，
 * 则判定为恶意刷票，要取消该用户投票的资格，当然同时也要取消他所投的票；如果一个用户的投票次数超过八次，将进入
 * 黑名单，禁止再次登录和使用系统。
 * 要使用状态模式实现，首先需要把投票过程的各种状态定义出来，根据以上描述大致分为四种状态：正常投票、反复投票、
 * 恶意刷票、进入黑名单。然后创建一个投票管理对象(相当于Context)。
 * <p/>
 * 通过本示例可以看出，状态的转换基本上都是内部行为，主要在状态模式内部维护。
 * 比如，对于投票的人员，任何时候他的操作都是投票，但是投票管理对象的处理却不一定一样，会根据投票的次数来判断状态，
 * 然后根据状态去选择不同的处理。
 * <p/>
 * 状态模式的优点：
 * 1、状态模式将与特定状态相关的行为局部化，并且将不同状态的行为分割开来；
 * 2、所有状态相关的代码都存在于某个具体状态类(ConcreteState)中，所以通过定义新的子类很容易地增加新的状态和转换；
 * 3、状态模式通过把各种状态转移逻辑分布到状态角色(State)的子类之间，来减少相互间的依赖。
 * 状态模式的缺点：
 * 1、状态模式的使用必然会增加系统类和对象的个数；
 * 2、状态模式的结构与实现都较为复杂，如果使用不当将导致程序结构和代码的混乱；
 * 3、状态模式对"开闭原则"的支持并不太好，对于可以切换状态的状态模式，增加新的状态类需要修改那些负责状态转换的源代码，
 * 否则无法切换到新增状态；而且修改某个状态类的行为也需要修改对应类的源代码。
 * <p/>
 * 状态模式的适用场景：
 * 1、对象的行为依赖于它的状态(属性)并且可以根据它的状态改变而改变它的相关行为；
 * 2、代码中包含大量与对象状态有关的条件语句。
 */

public class State2TestCase extends TestCase {
    public void testState() {
        System.out.println("= = = = ↓↓↓状态模式(State)--在状态的处理类中进行状态的维护和转换，测试开始↓↓↓ = = = =");
        VoteManager manager = new VoteManager();
        for (int i = 0; i < 8; i++) {
            manager.vote("JOE", "A");
        }
        System.out.println("= = = = ↑↑↑状态模式(State)--在状态的处理类中进行状态的维护和转换，测试结束↑↑↑ = = = =");
    }
}
